package com.bjpowernode.service.impl;

import com.bjpowernode.constant.Constants;
import com.bjpowernode.manager.RedisManager;
import com.bjpowernode.mapper.TPermissionMapper;
import com.bjpowernode.mapper.TRoleMapper;
import com.bjpowernode.mapper.TUserMapper;
import com.bjpowernode.model.TPermission;
import com.bjpowernode.model.TRole;
import com.bjpowernode.model.TUser;
import com.bjpowernode.query.UserQuery;
import com.bjpowernode.service.UserService;
import com.bjpowernode.util.CacheUtils;
import com.bjpowernode.util.JWTUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private TUserMapper tUserMapper;

    @Resource
    private TRoleMapper tRoleMapper;

    @Resource
    private TPermissionMapper tPermissionMapper;

    @Resource
    private RedisManager redisManager;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //从数据库查询用户即可
        TUser tUser = tUserMapper.selectByUsername(username);

        if (tUser == null) {
            throw new UsernameNotFoundException("用户不存在");
        }

        //查询当前登录的人是什么角色
        //List<TRole> roleList = tRoleMapper.selectByUserId(tUser.getId());

        /*String[] roleAuthorities = new String[roleList.size()];
        for (int i = 0; i < roleList.size(); i++) {
            roleAuthorities[i] = roleList.get(i).getRolename();
        }*/

        //查询当前登录的人有哪些权限（权限标识符）
        List<TPermission> permissionList = tPermissionMapper.selectByUserId(tUser.getId());
        Collection<String> permissionAuthorities = new ArrayList<>();
        permissionList.forEach( tPermission -> {
            if (StringUtils.hasText(tPermission.getCode())) {
                permissionAuthorities.add(tPermission.getCode());
            }
        });

        //查询用户有哪些菜单权限
        List<TPermission> menuPermissionList = tPermissionMapper.selectMenuByUserId(tUser.getId());

        /*UserDetails userDetails = User.builder()
                .username(tUser.getUsername())
                .password(tUser.getPassword())
                .authorities(permissionAuthorities) //配置权限
                //.authorities(roleAuthorities) //配置角色，这么配置角色是不行的
                .roles(roleAuthorities) //配置角色，需要用这个方法
                .build();*/

        //角色和权限不能同时配置的，如果都配置了，后面配置的会覆盖前面的

        //或者这么写
        //UserDetails userDetails2 = new User(tUser.getUsername(), tUser.getPassword(), AuthorityUtils.NO_AUTHORITIES);

        tUser.authorities(permissionAuthorities); //配置权限
        //tUser.roles(roleAuthorities); //配置角色，需要用这个方法
        tUser.setMenuPermissionList(menuPermissionList); //设置用户的菜单权限

        return tUser;
    }

    @Override
    public PageInfo<TUser> getUserByPage(Integer current) {
        //1.设置PageHelper
        PageHelper.startPage(current, Constants.PAGE_SIZE);
        //2.查询
        List<TUser> list = tUserMapper.selectUserPage();
        //3.封装分页数据到PageInfo
        PageInfo<TUser> info = new PageInfo<>(list);
        return info;
    }

    @Override
    public TUser getUserById(Integer id) {
        TUser tUser = tUserMapper.selectUserDetailById(id);
        if (tUser.getCreateByDO() == null) {
            tUser.setCreateByDO(new TUser());
        }
        if (tUser.getEditByDO() == null) {
            tUser.setEditByDO(new TUser());
        }
        return tUser;
    }

    /**
     * 新增用户提交保存
     *
     * @param userQuery
     * @return
     */
    @Override
    public int saveUser(UserQuery userQuery) {
        TUser tUser = new TUser();

        //需要把UserQuery数据复制到TUser对象中
        //spring提供了一个工具类：BeanUtils，它可以实现把一个对象的属性值复制到另一个对象中
        //复制的要求：源对象和目标对象，两个对象的成员变量名称相同，成员变量的类型也相同，这样才可以复制
        BeanUtils.copyProperties(userQuery, tUser);

        //设置加密后的密码
        tUser.setLoginPwd(passwordEncoder.encode(userQuery.getLoginPwd()));

        //设置一下创建时间
        tUser.setCreateTime(new Date());

        //设置一下创建人
        Integer loginUserId = JWTUtil.parseUserFromJWT(userQuery.getJwt()).getId();
        tUser.setCreateBy(loginUserId);

        return tUserMapper.insertSelective(tUser);
    }

    /**
     * 编辑用户提交保存
     *
     * @param userQuery
     * @return
     */
    @Override
    public int updateUser(UserQuery userQuery) {
        TUser tUser = new TUser();

        //需要把UserQuery数据复制到TUser对象中
        //spring提供了一个工具类：BeanUtils，它可以实现把一个对象的属性值复制到另一个对象中
        //复制的要求：源对象和目标对象，两个对象的成员变量名称相同，成员变量的类型也相同，这样才可以复制
        BeanUtils.copyProperties(userQuery, tUser);

        //设置加密后的密码
        if (StringUtils.hasText(userQuery.getLoginPwd())) {
            tUser.setLoginPwd(passwordEncoder.encode(userQuery.getLoginPwd()));
        }

        //设置一下编辑时间
        tUser.setEditTime(new Date());

        //设置一下编辑人
        Integer loginUserId = JWTUtil.parseUserFromJWT(userQuery.getJwt()).getId();
        tUser.setEditBy(loginUserId);

        return tUserMapper.updateByPrimaryKeySelective(tUser);
    }

    /**
     * 更新用户登录时间
     *
     * @param id
     * @return
     */
    @Override
    public int updateLoginTimeById(Integer id) {
        TUser tUser = new TUser();
        tUser.setId(id);
        tUser.setLastLoginTime(new Date());
        return tUserMapper.updateByPrimaryKeySelective(tUser);
    }

    /**
     * 根据id删除用户
     *
     * @param id
     * @return
     */
    @Override
    public int delUserById(Integer id) {
        return tUserMapper.deleteByPrimaryKey(id);
    }

    /**
     * 根据id批量删除用户
     *
     * @param idList
     * @return
     */
    @Override
    public int batchDelUserById(List<String> idList) {
        return tUserMapper.deleteByIds(idList);
    }

    /**
     * 查询负责人（所有）
     *
     * @return
     */
    @Override
    public List<TUser> getOwnerUser() {
        //查询所有负责人，可能有多处业务需要查所有负责人，那么为了减少对数据库的查询次数，可以加入缓存功能
        //比如缓存3分钟，那么在这3分钟内，我就不需要查询数据库了，减少了数据库的压力，这是代码的一个优化
        //实现逻辑：
        //1、先从缓存中查询，如果查到了就直接返回，此时就不需要查询数据库了，
        //2、如果缓存中没有查到，那就从数据库查询，然后把数据放入缓存中，
        //3、那么下次查询的时候，又可以从缓存中查询，整个下来，可以减少对数据库的查询，降低数据库的压力

        List<TUser> ownerUserList = CacheUtils.getCacheData(
                () -> (List<TUser>)redisManager.getValue(Constants.REDIS_OWNER_KEY),
                () -> tUserMapper.selectOwnerUser(),
                (t) -> redisManager.setValue(Constants.REDIS_OWNER_KEY, t, Constants.OPTIONS_EXPIRE_TIME, TimeUnit.MINUTES)
        );
        return ownerUserList;
    }
}
